{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Hadamard Multitask GP Regression\n",
    "\n",
    "## Introduction\n",
    "\n",
    "This notebook demonstrates how to perform \"Hadamard\" multitask regression. \n",
    "This differs from the [multitask gp regression example notebook](./Multitask_GP_Regression.ipynb) in one key way:\n",
    "\n",
    "- Here, we assume that we have observations for **one task per input**. For each input, we specify the task of the input that we observe. (The kernel that we learn is expressed as a Hadamard product of an input kernel and a task kernel)\n",
    "- In the other notebook, we assume that we observe all tasks per input. (The kernel in that notebook is the Kronecker product of an input kernel and a task kernel).\n",
    "\n",
    "Multitask regression, first introduced in [this paper](https://papers.nips.cc/paper/3189-multi-task-gaussian-process-prediction.pdf) learns similarities in the outputs simultaneously. It's useful when you are performing regression on multiple functions that share the same inputs, especially if they have similarities (such as being sinusodial).\n",
    "\n",
    "Given inputs $x$ and $x'$, and tasks $i$ and $j$, the covariance between two datapoints and two tasks is given by\n",
    "\n",
    "$$  k([x, i], [x', j]) = k_\\text{inputs}(x, x') * k_\\text{tasks}(i, j)\n",
    "$$\n",
    "\n",
    "where $k_\\text{inputs}$ is a standard kernel (e.g. RBF) that operates on the inputs.\n",
    "$k_\\text{task}$ is a special kernel - the `IndexKernel` - which is a lookup table containing inter-task covariance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import math\n",
    "import torch\n",
    "import gpytorch\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "%matplotlib inline\n",
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set up training data\n",
    "\n",
    "In the next cell, we set up the training data for this example. For each task we'll be using 50 random points on [0,1), which we evaluate the function on and add Gaussian noise to get the training labels. Note that different inputs are used for each task.\n",
    "\n",
    "We'll have two functions - a sine function (y1) and a cosine function (y2)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_x1 = torch.rand(50)\n",
    "train_x2 = torch.rand(50)\n",
    "\n",
    "train_y1 = torch.sin(train_x1 * (2 * math.pi)) + torch.randn(train_x1.size()) * 0.2\n",
    "train_y2 = torch.cos(train_x2 * (2 * math.pi)) + torch.randn(train_x2.size()) * 0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set up a Hadamard multitask model\n",
    "\n",
    "The model should be somewhat similar to the `ExactGP` model in the [simple regression example](../01_Exact_GPs/Simple_GP_Regression.ipynb).\n",
    "\n",
    "The differences:\n",
    "\n",
    "1. The model takes two input: the inputs (x) and indices. The indices indicate which task the observation is for.\n",
    "2. Rather than just using a RBFKernel, we're using that in conjunction with a IndexKernel.\n",
    "3. We don't use a ScaleKernel, since the IndexKernel will do some scaling for us. (This way we're not overparameterizing the kernel.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MultitaskGPModel(gpytorch.models.ExactGP):\n",
    "    def __init__(self, train_x, train_y, likelihood):\n",
    "        super(MultitaskGPModel, self).__init__(train_x, train_y, likelihood)\n",
    "        self.mean_module = gpytorch.means.ConstantMean()\n",
    "        self.covar_module = gpytorch.kernels.RBFKernel()\n",
    "        \n",
    "        # We learn an IndexKernel for 2 tasks\n",
    "        # (so we'll actually learn 2x2=4 tasks with correlations)\n",
    "        self.task_covar_module = gpytorch.kernels.IndexKernel(num_tasks=2, rank=1)\n",
    "\n",
    "    def forward(self,x,i):\n",
    "        mean_x = self.mean_module(x)\n",
    "        \n",
    "        # Get input-input covariance\n",
    "        covar_x = self.covar_module(x)\n",
    "        # Get task-task covariance\n",
    "        covar_i = self.task_covar_module(i)\n",
    "        # Multiply the two together to get the covariance we want\n",
    "        covar = covar_x.mul(covar_i)\n",
    "        \n",
    "        return gpytorch.distributions.MultivariateNormal(mean_x, covar)\n",
    "\n",
    "likelihood = gpytorch.likelihoods.GaussianLikelihood()\n",
    "\n",
    "train_i_task1 = torch.full_like(train_x1, dtype=torch.long, fill_value=0)\n",
    "train_i_task2 = torch.full_like(train_x2, dtype=torch.long, fill_value=1)\n",
    "\n",
    "full_train_x = torch.cat([train_x1, train_x2])\n",
    "full_train_i = torch.cat([train_i_task1, train_i_task2])\n",
    "full_train_y = torch.cat([train_y1, train_y2])\n",
    "\n",
    "# Here we have two iterms that we're passing in as train_inputs\n",
    "model = MultitaskGPModel((full_train_x, full_train_i), full_train_y, likelihood)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training the model\n",
    "\n",
    "In the next cell, we handle using Type-II MLE to train the hyperparameters of the Gaussian process.\n",
    "\n",
    "See the [simple regression example](../01_Exact_GPs/Simple_GP_Regression.ipynb) for more info on this step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iter 1/50 - Loss: 0.956\n",
      "Iter 2/50 - Loss: 0.916\n",
      "Iter 3/50 - Loss: 0.877\n",
      "Iter 4/50 - Loss: 0.839\n",
      "Iter 5/50 - Loss: 0.803\n",
      "Iter 6/50 - Loss: 0.767\n",
      "Iter 7/50 - Loss: 0.730\n",
      "Iter 8/50 - Loss: 0.692\n",
      "Iter 9/50 - Loss: 0.653\n",
      "Iter 10/50 - Loss: 0.613\n",
      "Iter 11/50 - Loss: 0.575\n",
      "Iter 12/50 - Loss: 0.539\n",
      "Iter 13/50 - Loss: 0.504\n",
      "Iter 14/50 - Loss: 0.470\n",
      "Iter 15/50 - Loss: 0.435\n",
      "Iter 16/50 - Loss: 0.399\n",
      "Iter 17/50 - Loss: 0.362\n",
      "Iter 18/50 - Loss: 0.325\n",
      "Iter 19/50 - Loss: 0.287\n",
      "Iter 20/50 - Loss: 0.250\n",
      "Iter 21/50 - Loss: 0.215\n",
      "Iter 22/50 - Loss: 0.182\n",
      "Iter 23/50 - Loss: 0.151\n",
      "Iter 24/50 - Loss: 0.122\n",
      "Iter 25/50 - Loss: 0.093\n",
      "Iter 26/50 - Loss: 0.066\n",
      "Iter 27/50 - Loss: 0.040\n",
      "Iter 28/50 - Loss: 0.016\n",
      "Iter 29/50 - Loss: -0.005\n",
      "Iter 30/50 - Loss: -0.022\n",
      "Iter 31/50 - Loss: -0.037\n",
      "Iter 32/50 - Loss: -0.049\n",
      "Iter 33/50 - Loss: -0.059\n",
      "Iter 34/50 - Loss: -0.066\n",
      "Iter 35/50 - Loss: -0.071\n",
      "Iter 36/50 - Loss: -0.074\n",
      "Iter 37/50 - Loss: -0.075\n",
      "Iter 38/50 - Loss: -0.074\n",
      "Iter 39/50 - Loss: -0.071\n",
      "Iter 40/50 - Loss: -0.068\n",
      "Iter 41/50 - Loss: -0.065\n",
      "Iter 42/50 - Loss: -0.062\n",
      "Iter 43/50 - Loss: -0.060\n",
      "Iter 44/50 - Loss: -0.058\n",
      "Iter 45/50 - Loss: -0.057\n",
      "Iter 46/50 - Loss: -0.056\n",
      "Iter 47/50 - Loss: -0.057\n",
      "Iter 48/50 - Loss: -0.058\n",
      "Iter 49/50 - Loss: -0.060\n",
      "Iter 50/50 - Loss: -0.062\n"
     ]
    }
   ],
   "source": [
    "# this is for running the notebook in our testing framework\n",
    "import os\n",
    "smoke_test = ('CI' in os.environ)\n",
    "training_iterations = 2 if smoke_test else 50\n",
    "\n",
    "\n",
    "# Find optimal model hyperparameters\n",
    "model.train()\n",
    "likelihood.train()\n",
    "\n",
    "# Use the adam optimizer\n",
    "optimizer = torch.optim.Adam([\n",
    "    {'params': model.parameters()},  # Includes GaussianLikelihood parameters\n",
    "], lr=0.1)\n",
    "\n",
    "# \"Loss\" for GPs - the marginal log likelihood\n",
    "mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)\n",
    "\n",
    "for i in range(training_iterations):\n",
    "    optimizer.zero_grad()\n",
    "    output = model(full_train_x, full_train_i)\n",
    "    loss = -mll(output, full_train_y)\n",
    "    loss.backward()\n",
    "    print('Iter %d/50 - Loss: %.3f' % (i + 1, loss.item()))\n",
    "    optimizer.step()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Make predictions with the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x216 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Set into eval mode\n",
    "model.eval()\n",
    "likelihood.eval()\n",
    "\n",
    "# Initialize plots\n",
    "f, (y1_ax, y2_ax) = plt.subplots(1, 2, figsize=(8, 3))\n",
    "\n",
    "# Test points every 0.02 in [0,1]\n",
    "test_x = torch.linspace(0, 1, 51)\n",
    "tast_i_task1 = torch.full_like(test_x, dtype=torch.long, fill_value=0)\n",
    "test_i_task2 = torch.full_like(test_x, dtype=torch.long, fill_value=1)\n",
    "\n",
    "# Make predictions - one task at a time\n",
    "# We control the task we cae about using the indices\n",
    "\n",
    "# The gpytorch.settings.fast_pred_var flag activates LOVE (for fast variances)\n",
    "# See https://arxiv.org/abs/1803.06058\n",
    "with torch.no_grad(), gpytorch.settings.fast_pred_var():\n",
    "    observed_pred_y1 = likelihood(model(test_x, tast_i_task1))\n",
    "    observed_pred_y2 = likelihood(model(test_x, test_i_task2))\n",
    "\n",
    "# Define plotting function\n",
    "def ax_plot(ax, train_y, train_x, rand_var, title):\n",
    "    # Get lower and upper confidence bounds\n",
    "    lower, upper = rand_var.confidence_region()\n",
    "    # Plot training data as black stars\n",
    "    ax.plot(train_x.detach().numpy(), train_y.detach().numpy(), 'k*')\n",
    "    # Predictive mean as blue line\n",
    "    ax.plot(test_x.detach().numpy(), rand_var.mean.detach().numpy(), 'b')\n",
    "    # Shade in confidence \n",
    "    ax.fill_between(test_x.detach().numpy(), lower.detach().numpy(), upper.detach().numpy(), alpha=0.5)\n",
    "    ax.set_ylim([-3, 3])\n",
    "    ax.legend(['Observed Data', 'Mean', 'Confidence'])\n",
    "    ax.set_title(title)\n",
    "\n",
    "# Plot both tasks\n",
    "ax_plot(y1_ax, train_y1, train_x1, observed_pred_y1, 'Observed Values (Likelihood)')\n",
    "ax_plot(y2_ax, train_y2, train_x2, observed_pred_y2, 'Observed Values (Likelihood)')"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
